/*
 *   Copyright 2008 Luca Bellonda <lbellonda@gmail.com>
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Library General Public License as
 *   published by the Free Software Foundation; either version 2 or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details
 *
 *   You should have received a copy of the GNU Library General Public
 *   License along with this program; if not, write to the
 *   Free Software Foundation, Inc.,
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include "dbusapplet.h"

#include <QAction>
#include <QGraphicsLinearLayout>
#include <QGraphicsView>

#include <Plasma/WebView>
#include <Plasma/ToolTipManager>
#include <Plasma/DataEngine>
#include <Plasma/Theme>
#include <KStandardDirs>
#include <KTextEdit>
#include <QTextDocument>
#include <QWebFrame>
#include <QWebPage>
#include <QtWebKit>
#include <QDir>

#include <stdio.h>

#define ENGINE_NAME     "dbusengine"
#define TEMPLATE_PATH   "dbusapplet/data.html"
#define SOURCE_SYSTEM_SERVICES "SystemServices"
#define SOURCE_SESSION_SERVICES "SessionServices"
#define SERVICE_ID  "SERVICE"

#define INFO_ROW_L  "<li class=\"infoRowL\"> <span class=\"type1\">%1</span> <span class=\"name\"> %2</span></li>\n"
#define INFO_ROW_SERVICE_L  "<li class=\"infoRowSL\">%1</li>\n"
#define  NO_DATA "<b>No Data Available</b><br/>\n"
#define STR_ERROR   "ERROR"

#define COMPILATA   2
//#define DUMP
#ifdef DUMP
#define   D(x)    x
static void dump(QString &str)
{
    printf("%s\n", str.toAscii().data());
}

#else
#define   D(x)
#define   dump(x)
#endif

DBusApplet::DBusApplet(QObject *parent, const QVariantList &args)
        : Plasma::PopupApplet(parent, args)
{
    D(printf("Compilata %d\n", COMPILATA));
    m_mainLayout = NULL;
    m_template = readDataFile(TEMPLATE_PATH);
    m_DBusEngine = NULL ;
    m_src = SOURCE_SYSTEM_SERVICES ;
    m_info = new Plasma::WebView(this);
    QWebPage *page = new QWebPage();
    connect(page, SIGNAL(frameCreated(QWebFrame *)), this, SLOT(connectFrame(QWebFrame *)));
    connect(m_info, SIGNAL(loadFinished(bool)), this, SLOT(loadFinished(bool)));
    m_info->setPage(page);

    m_orientation = Qt::Vertical ;
    setBackgroundHints(DefaultBackground);

    D(printf("DBusApplet Started..................\n"));
    setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
    connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), this, SLOT(updateView()));
    resize(200, 200);
    mainLayout()->addItem(m_info);
    updateView();
}

DBusApplet::~DBusApplet()
{
}


QGraphicsLinearLayout* DBusApplet::mainLayout()
{
    if (NULL == m_mainLayout) {
        m_mainLayout = new QGraphicsLinearLayout(m_orientation);
        m_mainLayout->setContentsMargins(0, 0, 0, 0);
        m_mainLayout->setSpacing(0);
        setLayout(m_mainLayout);
    }
    return m_mainLayout;
}

void DBusApplet::init()
{
    m_DBusEngine = dataEngine(ENGINE_NAME);
    if (! m_DBusEngine->isValid()) {
        setFailedToLaunch(true, i18n("Failed to load dbus DataEngine"));
        return;
    }
    m_DBusEngine->connectSource(m_src, this);
}

void DBusApplet::paintInterface(QPainter *p,
                                const QStyleOptionGraphicsItem * /*option*/, const QRect &contentsRect)
{
    p->setRenderHint(QPainter::SmoothPixmapTransform);
    p->setRenderHint(QPainter::Antialiasing);
    p->save();
    p->setPen(Qt::white);
    p->drawText(contentsRect, Qt::AlignBottom | Qt::AlignHCenter, "dbus applet");
    p->restore();
}

void DBusApplet::dataUpdated(const QString& source, const Plasma::DataEngine::Data &data)
{
    D(printf("data updated\n"));
    if (data.isEmpty()) {
        D(printf("*empty\n"));
        return;
    }
    foreach(const QString &id, data.keys()) {
        D(printf("*un dato "));
        QVariant v = data.value(id);
        D(printf(" figli %d\n", v.value<DBusAppletItem>().childs.size()));
        if (source == SOURCE_SESSION_SERVICES) {
            m_lastDataSession = DBusAppletItem(v.value<DBusAppletItem>()) ;
        } else {
            m_lastDataSystem = DBusAppletItem(v.value<DBusAppletItem>()) ;
        }
    }
    updateView();
}

void DBusApplet::reload(const QString &selection)
{
    D(printf("reload me %s\n", selection.toAscii().data()));
    m_DBusEngine->disconnectSource(m_src, this);
    if (selection == "y")
        m_src = SOURCE_SYSTEM_SERVICES;
    else
        m_src = SOURCE_SESSION_SERVICES;
    m_DBusEngine->connectSource(m_src, this);
    m_template = readDataFile(TEMPLATE_PATH);
}

void DBusApplet::populateJavaScriptWindowObject()
{
    D(printf("populating..\n"));
    if (NULL == m_info)
        return ;
    m_info->page()->mainFrame()->addToJavaScriptWindowObject("appletInterface", this);
}

void DBusApplet::connectFrame(QWebFrame *frame)
{
    D(printf("new frame.....\n"));
    connect(frame, SIGNAL(javaScriptWindowObjectCleared()), this, SLOT(populateJavaScriptWindowObject()));
}

void    DBusApplet::loadFinished(bool /*success*/)
{
    D(printf("loadFinished..................\n"));
}

QString DBusApplet::readDataFile(const QString inputPath)
{
    QString dataFile = KStandardDirs::locate("data", "desktoptheme/" + Plasma::Theme::defaultTheme()->themeName() + "/" + inputPath);
    D(printf(" Current dir is %s and %s\n", QDir::currentPath().toAscii().data(), dataFile.toAscii().data()));
    QFile file(dataFile);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        D(printf(" no file %s\n", inputPath.toAscii().data()));
        return "";
    }
    QTextStream inStream(&file);
    QTextCodec *codec = QTextCodec::codecForName("utf8");
    inStream.setCodec(codec);
    QString data = inStream.readAll();
    D(printf("%s\n", data.toAscii().data()));
    return data;
}

void DBusApplet::scanChildrens(DBusAppletItem* obj, QString &html, const int watchdog)
{
    int wdog = watchdog ;
    wdog++;
    if (wdog > 100) {
        D(printf("watchdog\n"));
        return ;
    }
    int size = obj->childs.size();
    if (size > 0) {
        html += "<ul>\n";
        for (int i = 0; i < size; i++) {
            DBusAppletItem* child = obj->childs.at(i);
            if (NULL == child) {
                D(printf("child null \n"));
                continue;
            }
            html += QString(INFO_ROW_L).arg(child->type).arg(child->data);
            scanChildrens(child, html, wdog);
        }
        html += "</ul>\n";
    }
}


void DBusApplet::updateView()
{
    D(printf(" updateView()"));
    if (NULL == m_info)
        return ;
    D(printf(" looking for data ()"));
    QString html ;
    QString html_rows = "";
    DBusAppletItem &src = m_lastDataSystem ;
    if (m_src == SOURCE_SESSION_SERVICES) {
        src = m_lastDataSession ;
    }
    int size = src.childs.size();
    if (size == 0) {
        html_rows = NO_DATA;
    } else {
        html += "<ul>\n";
        D(printf("ECCO\n"));
        for (int i = 0; i < size ; i++) {
            DBusAppletItem* topObject = src.childs.at(i);
            D(printf("ECCO 2 %s\n", topObject->data.toAscii().data()));
            html_rows += QString(INFO_ROW_SERVICE_L).arg(topObject->data);
            scanChildrens(topObject, html_rows, 0);
        }
        html += "</ul>\n";
    }

    QString selSession, selSystem;
    if (m_src == SOURCE_SESSION_SERVICES)
        selSession = "SELECTED";
    else
        selSystem = "SELECTED";

    html = QString(m_template).arg(selSession).arg(selSystem).arg(m_src).arg(html_rows);
//////////////////////////////D(printf("About to set view data %s\n", html.toAscii().data()));
    connect(m_info->page()->mainFrame(), SIGNAL(javaScriptWindowObjectCleared()), this, SLOT(populateJavaScriptWindowObject()));

    m_info->setHtml(html);
    Plasma::ToolTipContent data(i18n("DBus Info"), html);
}

void DBusApplet::constraintsEvent(Plasma::Constraints constraints)
{
    if (constraints & Plasma::FormFactorConstraint) {
        switch (formFactor()) {
        case Plasma::Planar:
        case Plasma::MediaCenter:
            m_orientation = Qt::Vertical;
            break;
        case Plasma::Horizontal:
            m_orientation = Qt::Horizontal;
            break;
        case Plasma::Vertical:
            m_orientation = Qt::Vertical;
            break;
        }
    } else if (constraints & Plasma::SizeConstraint) {
        ;
    }
    QGraphicsLinearLayout* l = mainLayout();
    if (NULL != l) {
        l->invalidate();
    }
}


#include "dbusapplet.moc"
